package com.zmykj.hik.hikService.Service.Stream;

import com.zmykj.hik.hikService.Common.CommonClass;
import com.zmykj.hik.hikService.Common.CommonClass.StringPointer;
import com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.PREVIEW_NEWLINK_CB;
import com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.PREVIEW_DATA_CB;
import com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.NET_EHOME_PREVIEW_CB_MSG;
import com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.NET_EHOME_NEWLINK_CB_MSG;
import com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.NET_EHOME_LISTEN_PREVIEW_CFG;
import com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.NET_EHOME_PREVIEW_DATA_CB_PARAM;
import com.zmykj.hik.hikService.Common.CommonMethod;

import com.sun.jna.Native;
import com.sun.jna.NativeLong;
import com.sun.jna.Pointer;

import static com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.NET_DVR_STREAMDATA;
import static com.zmykj.hik.hikService.Service.Stream.ISUPStreamByJNA.NET_DVR_SYSHEAD;

public class EStream {
    private boolean m_bIsRunning = false;
    private static ISUPStreamByJNA m_StreamInstance = null;
    private static NET_EHOME_LISTEN_PREVIEW_CFG m_struSSListenParam = new NET_EHOME_LISTEN_PREVIEW_CFG();
    private static NET_EHOME_PREVIEW_DATA_CB_PARAM m_struDataCB = new NET_EHOME_PREVIEW_DATA_CB_PARAM();
    private static FPreviewNewLinkCallBack fnPreviewNewLinkCallBack = null;
    private static FPreviewDataCallback fnPreviewDateCallBack = null;
    public static NativeLong m_lPreviewListenHandle;
    public static NativeLong m_lNewLinkHandle;

    public EStream(){
        if(m_StreamInstance == null)
        {
            if(!CreateStreamInstance())
            {
                System.out.println("Load Stream module fail");
                return;
            }
        }

        if(!m_StreamInstance.NET_ESTREAM_Init()) {
            CommonMethod.logRecord("INFO", "[NET_ESTREAM_Init]->ESTREAM initiate failed! errCode:" + m_StreamInstance.NET_ESTREAM_GetLastError());
        }else{
            CommonMethod.logRecord("INFO", "[NET_ESTREAM_Init]->ESTREAM initiate Successfully!");

            m_StreamInstance.NET_ESTREAM_SetLogToFile(3, "./EHomeSdkLog", true);

            String sLibComPath = "";
            if(CommonMethod.isLinux())
            {
                sLibComPath = CommonMethod.GetLibPathByArch() + "HCAapSDKCom";
                StringPointer strPointer = new StringPointer(sLibComPath);
                strPointer.write();
                if(m_StreamInstance.NET_ESTREAM_SetSDKLocalCfg(5, strPointer.getPointer()))
                    System.out.println("[Stream]ComPath Load Successfully:" + sLibComPath);
                else
                    System.out.println("[Stream]ComPath Load Failed!:" + sLibComPath + ", errorCode: " + m_StreamInstance.NET_ESTREAM_GetLastError());

                strPointer.read();
            }

            try {
                CommonClass.NET_EHOME_LOCAL_ACCESS_SECURITY struAccessSecure = new CommonClass.NET_EHOME_LOCAL_ACCESS_SECURITY();
                struAccessSecure.byAccessSecurity = 0;
                struAccessSecure.dwSize = struAccessSecure.size();
                struAccessSecure.write();
                m_StreamInstance.NET_ESTREAM_SetSDKLocalCfg(0, struAccessSecure.getPointer());
            } catch (Exception ex) {
                ex.printStackTrace();
            }

            /*-------------Preview Listen Part----------------*/

            CommonMethod.ByteCopy(CommonMethod.GetListenInfo().struPreviewListenParam.struIPAdress.szIP, m_struSSListenParam.struIPAdress.szIP);
            m_struSSListenParam.struIPAdress.wPort = CommonMethod.GetListenInfo().struPreviewListenParam.struIPAdress.wPort;
            m_struSSListenParam.byLinkMode = CommonMethod.GetListenInfo().struPreviewListenParam.byLinkMode;
            if(fnPreviewNewLinkCallBack == null)
            {
                fnPreviewNewLinkCallBack = new FPreviewNewLinkCallBack();
            }
            m_struSSListenParam.fnNewLinkCB = fnPreviewNewLinkCallBack;

            m_lPreviewListenHandle = m_StreamInstance.NET_ESTREAM_StartListenPreview(m_struSSListenParam);
            if(m_lPreviewListenHandle.longValue() < 0)
            {
                CommonMethod.logRecord("ERROR", "NET_ESTREAM_StartListenPreview Failed," +
                        " errCode:"+ m_StreamInstance.NET_ESTREAM_GetLastError() +
                        " IP: " + CommonMethod.byteToString(m_struSSListenParam.struIPAdress.szIP) +
                        " port: " + m_struSSListenParam.struIPAdress.wPort +
                        " linkMode: " + m_struSSListenParam.byLinkMode);
            }else{
                m_bIsRunning = true;
                CommonMethod.logRecord("INFO", "NET_ESTREAM_StartListenPreview Success," +
                        " IP: " + CommonMethod.byteToString(m_struSSListenParam.struIPAdress.szIP) +
                        " port: " + m_struSSListenParam.struIPAdress.wPort +
                        " linkMode: " + m_struSSListenParam.byLinkMode);
            }

            /*-------------Playback Listen Part----------------*/
        }
    }

    public boolean StopEStream()
    {
        boolean bRet = true;
        if(m_lPreviewListenHandle.longValue() >= 0)
        {
            if(!m_StreamInstance.NET_ESTREAM_StopListenPreview(m_lPreviewListenHandle))
            {
                CommonMethod.logRecord("ERROR", "NET_ESTREAM_StopListenPreview failed, errCode:"
                + m_StreamInstance.NET_ESTREAM_GetLastError());
                bRet = false;
            }
            else
            {
                m_bIsRunning = false;
                m_lPreviewListenHandle.setValue(-1);
                CommonMethod.logRecord("INFO", "NET_ESTREAM_StopListenPreview Success!");

                bRet = false;
                if(!m_StreamInstance.NET_ESTREAM_Fini())
                {
                    CommonMethod.logRecord("ERROR", "NET_ESTREAM_Fini failed, errCode:"
                            + m_StreamInstance.NET_ESTREAM_GetLastError());
                }
                else
                {
                    CommonMethod.logRecord("INFO", "NET_ESTREAM_Fini Success!");
                }
            }
        }
        return true;
    }

    public class FPreviewNewLinkCallBack implements PREVIEW_NEWLINK_CB{
        public boolean invoke(NativeLong lLinkHandle, NET_EHOME_NEWLINK_CB_MSG pNewLinkCBMsg, Pointer pUserData){
            m_lNewLinkHandle = lLinkHandle;
            CommonMethod.logRecord("INFO", "Callback of preview listening, DeviceID:" + CommonMethod.byteToString(pNewLinkCBMsg.szDeviceID) +
                    "Channel:" + pNewLinkCBMsg.dwChannelNo);

            if(fnPreviewDateCallBack == null)
            {
                fnPreviewDateCallBack = new FPreviewDataCallback();
            }
            m_struDataCB.fnPreviewDataCB = fnPreviewDateCallBack;
            m_struDataCB.byStreamFormat = 0;      //PS

            if(!EStream.m_StreamInstance.NET_ESTREAM_SetPreviewDataCB(lLinkHandle, m_struDataCB))
            {
                CommonMethod.logRecord("ERROR", "NET_ESTREAM_SetPreviewDataCB failed, errCode is:" + EStream.m_StreamInstance.NET_ESTREAM_GetLastError());
                return false;
            }

            CommonMethod.logRecord("INFO", "NET_ESTREAM_SetPreviewDataCB Success!");
            return true;
        }
    }

    public class FPreviewDataCallback implements PREVIEW_DATA_CB {
        public boolean invoke(NativeLong iPreviewHandle, Pointer pPreviewCBMsg, Pointer pUserData)
        {
            try{
                String sClassName = NET_EHOME_PREVIEW_CB_MSG.class.getName();
                NET_EHOME_PREVIEW_CB_MSG strPreviewData = (NET_EHOME_PREVIEW_CB_MSG) CommonMethod.WritePointerDataToClass(pPreviewCBMsg, sClassName);
                if(strPreviewData.pRecvdata == null || strPreviewData.dwDataLen <= 0)
                {
                    return false;
                }

                switch (strPreviewData.byDataType)
                {
                    case NET_DVR_SYSHEAD: {
                        System.out.println("HIK Stream Header len:" + strPreviewData.dwDataLen);
                        break;
                    }
                    case NET_DVR_STREAMDATA:
                    {
                        System.out.println("Stream data len" + strPreviewData.dwDataLen);
                    }
                }
            }catch(Exception ex){
                ex.printStackTrace();
            }
            return true;
        }
    }

    private static boolean CreateStreamInstance()
    {
        if(m_StreamInstance == null)
        {
            synchronized (ISUPStreamByJNA.class)
            {
                String strDllPath = "";
                try
                {
                    if(CommonMethod.isWindows())
                        strDllPath = CommonMethod.GetLibPathByArch() + "HCISUPStream";
                    else if(CommonMethod.isLinux())
                        strDllPath = CommonMethod.GetLibPathByArch() + "libHCISUPStream.so";
                    m_StreamInstance = (ISUPStreamByJNA) Native.loadLibrary(strDllPath, ISUPStreamByJNA.class);
                }catch (Exception ex) {
                    System.out.println("loadLibrary: " + strDllPath + " Error: " + ex.getMessage());
                    return false;
                }
            }
        }
        return true;
    }

    public static ISUPStreamByJNA GetStreamInstance()
    {
        return m_StreamInstance;
    }

    public boolean IsRunning(){return m_bIsRunning;}
}